package org.light.generator;

import java.util.ArrayList;
import java.util.List;

import org.light.core.Writeable;
import org.light.domain.Domain;
import org.light.domain.Statement;
import org.light.domain.StatementList;
import org.light.utils.WriteableUtil;

public class DomainModGenerator extends Generator{
	protected List<Domain> domains = new ArrayList<>();
	protected boolean containsAuth = false;
	
	public boolean isContainsAuth() {
		return containsAuth;
	}

	public void setContainsAuth(boolean containsAuth) {
		this.containsAuth = containsAuth;
	}

	public List<Domain> getDomains() {
		return domains;
	}

	public void setDomains(List<Domain> domains) {
		this.domains = domains;
	}

	public DomainModGenerator(){
		super();
		super.fileName = "mod.rs";
		super.standardName = "DomainMod";
	}

	@Override
	public StatementList generateStatementList() {
		List<Writeable> sList = new ArrayList<Writeable>();
		sList.add(new Statement(100L,0,"#![allow(dead_code)]"));
		sList.add(new Statement(500L,0,"mod count_num;"));
		long serial = 1000L;
		for (Domain domain : this.getDomains()) {
			sList.add(new Statement(serial,0,"mod "+domain.getSnakeDomainNameWithSuffix()+";"));
			serial += 1000L;
		}		
		
		if (containsAuth) {
			sList.add(new Statement(serial,0,"pub mod dto;"));
			sList.add(new Statement(serial+1000L,0,"pub mod error;"));
		}
		
		sList.add(new Statement(serial+2000L,0,""));
		sList.add(new Statement(serial+3000L,0,"pub type CountNum = count_num::CountNum;"));
		serial += 4000L;
		for (Domain domain : this.getDomains()) {
			sList.add(new Statement(serial,0,"pub type "+domain.getCapFirstDomainNameWithSuffix()+" = "+domain.getSnakeDomainNameWithSuffix()+"::"+domain.getCapFirstDomainNameWithSuffix()+";"));
			serial += 1000L;
		}
		sList.add(new Statement(serial,0,""));
		serial += 1000L;
		for (Domain domain : this.getDomains()) {
			sList.add(new Statement(serial,0,"pub type "+domain.getCapFirstDomainName()+"QueryRequest = "+domain.getSnakeDomainNameWithSuffix()+"::"+domain.getCapFirstDomainName()+"QueryRequest;"));
			serial += 1000L;
		}

		sList.add(new Statement(serial+1000L,0,""));
		sList.add(new Statement(serial+2000L,0,"pub mod my_date_time_format {"));
		sList.add(new Statement(serial+3000L,1,"use chrono::NaiveDateTime;"));
		sList.add(new Statement(serial+4000L,1,"use serde::{self, Deserialize, Serializer, Deserializer};"));
		sList.add(new Statement(serial+5000L,0,""));
		sList.add(new Statement(serial+6000L,1,"pub const DATE_TIME_FORMAT: &'static str = \"%Y-%m-%d %H:%M:%S\";"));
		sList.add(new Statement(serial+7000L,0,""));
		sList.add(new Statement(serial+8000L,1,"pub fn serialize<S>("));
		sList.add(new Statement(serial+9000L,2,"date: &Option<NaiveDateTime>,"));
		sList.add(new Statement(serial+10000L,2,"serializer: S,"));
		sList.add(new Statement(serial+11000L,1,") -> Result<S::Ok, S::Error>"));
		sList.add(new Statement(serial+12000L,1,"where"));
		sList.add(new Statement(serial+13000L,2,"S: Serializer,"));
		sList.add(new Statement(serial+14000L,1,"{"));
		sList.add(new Statement(serial+15000L,2,"match date {"));
		sList.add(new Statement(serial+16000L,3,"Some(date) => {"));
		sList.add(new Statement(serial+17000L,4,"let s = format!(\"{}\", date.format(DATE_TIME_FORMAT));"));
		sList.add(new Statement(serial+18000L,4,"serializer.serialize_str(&s)"));
		sList.add(new Statement(serial+19000L,3,"},"));
		sList.add(new Statement(serial+20000L,3,"None => serializer.serialize_str(\"\")"));
		sList.add(new Statement(serial+21000L,2,"}"));
		sList.add(new Statement(serial+22000L,1,"}"));
		sList.add(new Statement(serial+23000L,0,""));
		sList.add(new Statement(serial+24000L,1,"pub fn deserialize<'de, D>("));
		sList.add(new Statement(serial+25000L,2,"deserializer: D,"));
		sList.add(new Statement(serial+26000L,1,") -> Result<Option<NaiveDateTime>, D::Error>"));
		sList.add(new Statement(serial+27000L,1,"where"));
		sList.add(new Statement(serial+28000L,2,"D: Deserializer<'de>,"));
		sList.add(new Statement(serial+29000L,1,"{"));
		sList.add(new Statement(serial+30000L,2,"let s = String::deserialize(deserializer).unwrap();"));
		sList.add(new Statement(serial+31000L,2,"if s == \"\".to_string() {"));
		sList.add(new Statement(serial+32000L,3,"let result = NaiveDateTime::parse_from_str(&s,DATE_TIME_FORMAT).unwrap();"));
		sList.add(new Statement(serial+33000L,3,"Ok(Some(result))"));
		sList.add(new Statement(serial+34000L,2,"} else {"));
		sList.add(new Statement(serial+35000L,3,"Ok(Option::None)"));
		sList.add(new Statement(serial+36000L,2,"}"));
		sList.add(new Statement(serial+37000L,1,"}"));
		sList.add(new Statement(serial+38000L,0,"}"));
		sList.add(new Statement(serial+39000L,0,""));
		sList.add(new Statement(serial+40000L,0,"pub mod my_date_format {"));
		sList.add(new Statement(serial+41000L,1,"use chrono::NaiveDate;"));
		sList.add(new Statement(serial+42000L,1,"use serde::{self, Deserialize, Serializer, Deserializer};"));
		sList.add(new Statement(serial+43000L,1,"pub const DATE_FORMAT: &'static str = \"%Y-%m-%d\";"));
		sList.add(new Statement(serial+44000L,1,""));
		sList.add(new Statement(serial+45000L,1,"pub fn serialize<S>("));
		sList.add(new Statement(serial+46000L,2,"date: &Option<NaiveDate>,"));
		sList.add(new Statement(serial+47000L,2,"serializer: S,"));
		sList.add(new Statement(serial+48000L,1,") -> Result<S::Ok, S::Error>"));
		sList.add(new Statement(serial+49000L,1,"where"));
		sList.add(new Statement(serial+50000L,2,"S: Serializer,"));
		sList.add(new Statement(serial+51000L,1,"{"));
		sList.add(new Statement(serial+52000L,2,"match date {"));
		sList.add(new Statement(serial+53000L,3,"Some(date) => {"));
		sList.add(new Statement(serial+54000L,4,"let s = format!(\"{}\", date.format(DATE_FORMAT));"));
		sList.add(new Statement(serial+55000L,4,"serializer.serialize_str(&s)"));
		sList.add(new Statement(serial+56000L,3,"},"));
		sList.add(new Statement(serial+57000L,3,"None => {"));
		sList.add(new Statement(serial+58000L,4,"serializer.serialize_str(\"\")"));
		sList.add(new Statement(serial+59000L,3,"}"));
		sList.add(new Statement(serial+60000L,2,"}"));
		sList.add(new Statement(serial+61000L,1,"}"));
		sList.add(new Statement(serial+62000L,0,""));
		sList.add(new Statement(serial+63000L,1,"pub fn deserialize<'de, D>("));
		sList.add(new Statement(serial+64000L,2,"deserializer: D,"));
		sList.add(new Statement(serial+65000L,1,") -> Result<Option<NaiveDate>, D::Error>"));
		sList.add(new Statement(serial+66000L,1,"where"));
		sList.add(new Statement(serial+67000L,2,"D: Deserializer<'de>,"));
		sList.add(new Statement(serial+68000L,1,"{"));
		sList.add(new Statement(serial+69000L,2,"let s = String::deserialize(deserializer).unwrap();"));
		sList.add(new Statement(serial+70000L,2,"if s == \"\".to_string() {"));
		sList.add(new Statement(serial+71000L,3,"let result = NaiveDate::parse_from_str(&s,DATE_FORMAT).unwrap();"));
		sList.add(new Statement(serial+72000L,3,"Ok(Some(result))"));
		sList.add(new Statement(serial+73000L,2,"} else {"));
		sList.add(new Statement(serial+74000L,3,"Ok(Option::None)"));
		sList.add(new Statement(serial+75000L,2,"}"));
		sList.add(new Statement(serial+76000L,1,"}"));
		sList.add(new Statement(serial+77000L,0,"}"));
		
		return WriteableUtil.merge(sList);
	}

}
